#include "head.h"

union semun {
	int val;
	struct semid_ds * buffer;
	ushort * array;
};

int main(int argc, char ** argv) {
	key_t key_sem, key_full, key_empty, key_sha;
	key_sem = ftok("./producer.c", 16);
	key_full = ftok("./head.h", 32);
	key_empty = ftok("./head.h", 64);
	key_sha = ftok("./", 128);
	int id_sem, sem_full, sem_empty, id_sha, sem_count = 5, task_count = 5, producer_count = 10;
	id_sem = semget(key_sem, sem_count, IPC_CREAT | 0666);
	sem_full = semget(key_full, 1, IPC_CREAT | 0666);
	sem_empty = semget(key_empty, 1, IPC_CREAT | 0666);
	id_sha = shmget(key_sha, sizeof(struct task)*task_count, IPC_CREAT | 0666);
	if (id_sem == -1 || sem_full == -1 || sem_empty == -1 || id_sha == -1) {
		perror("semget/shmget");
		return -1;
	}
	
	struct task * tasks;
	if ((tasks = shmat(id_sha, (void *)0, 0)) == NULL) {
		perror("shmat");
		return -2;
	}
	int i;
	for (i = 0; i < task_count; i++) {
		tasks[i].operation = 1;	//tworzenie macierzy
	}
	union semun init;
	init.val = 1;
	for (i = 0; i < task_count; i++) {
		if (semctl(id_sem, i, SETVAL, init) == -1) {
			perror("semctl sem");
			return -3;
		}
	}
	init.val = task_count;
	if (semctl(sem_full, 0, SETVAL, init) == -1) {
		perror("semctl full");
		return -4;
	}
	init.val = 0;
	if (semctl(sem_empty, 0, SETVAL, init) == -1) {
		perror("semctl empty");
		return -5;
	}
	for (i = 0; i < producer_count; i++) {
		pid_t pid = fork();
		if (pid < 0) {
			perror("fork");
		} else if (pid == 0) {
			break;
		}
		sleep(1);
	}
	//int j;
	srand(time(NULL));
	//for (j = 0; j < 5; j++) {
	while (1) {
		struct task tmp;
		tmp.operation = 0;
		int k;
		for (i = 0; i < LENGTH; i++) {
			for (k = 0; k < LENGTH; k++) {
				tmp.matrix[i][k] = (double)rand()/RAND_MAX*100.0;
			}
		}
		struct sembuf sem_tmp1, sem_tmp2;
		sem_tmp1.sem_flg = 0;
		sem_tmp1.sem_num = 0;
		sem_tmp1.sem_op = -1;
		if (semop(sem_full, &sem_tmp1, 1) == -1) {
			perror("semop 1");
			//return -6;
		}
		for (i = 0; i < task_count; i++) {
			sleep(1);
			sem_tmp2.sem_flg = 0;
			sem_tmp2.sem_num = i;
			sem_tmp2.sem_op = -1;
			if (semop(id_sem, &sem_tmp2, 1) != -1) {
				if (tasks[i].operation == 1) {
					memcpy(&tasks[i], &tmp, sizeof(struct task));
					printf("Zadanie dołożone do pamięci\n");
					sem_tmp2.sem_flg = 0;
					sem_tmp2.sem_num = i;
					sem_tmp2.sem_op = 1;
					if (semop(id_sem, &sem_tmp2, 1) == -1) {
						perror("semop 3");
						//return -8;
					}
					sem_tmp2.sem_flg = 0;
					sem_tmp2.sem_num = 0;
					sem_tmp2.sem_op = 1;
					if (semop(sem_empty, &sem_tmp2, 1) == -1) {
						perror("semop 4");
						//return -9;
					}
					break;
				}
				sem_tmp2.sem_flg = 0;
				sem_tmp2.sem_num = i;
				sem_tmp2.sem_op = 1;
				if (semop(id_sem, &sem_tmp2, 1) == -1) {
					perror("semop 5");
					//return -10;
				}
			} else {
				perror("semop 2");
				//return -11;
			}
		}
	}
	return 0;
}
